import json
import re
import time
import unittest

import requests
from BeautifulReport import BeautifulReport as bf
import sys,os,django
path = '../lx_apitest'
sys.path.append(path)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'lx_apitest.settings')
django.setup()
from api_test.models import *

class Test(unittest.TestCase):

    # def test_01(self):
    #     print("我是第一个步骤")


    #  由于unittest 的类变量不可修改，该方法弃用，选择全局变量保存登录态
    # @classmethod
    # def setUpClass(cls) -> None:
    #     cls.login_res = ""

    def demo(self, step):
        # print(step.api_url)
        # 提取所有请求数据
        api_method = step.api_method
        api_url = step.api_url
        api_host = step.api_host
        api_header = step.api_header
        api_body_method = step.api_body_method
        api_body = step.api_body
        get_path = step.get_path
        get_zz = step.get_zz
        assert_zz = step.assert_zz
        assert_qz = step.assert_qz
        assert_path = step.assert_path
        mock_res = step.mock_res


        # 新增的mock 功能替代实际返回值
        if mock_res not in ["",None,'None']:
            res = mock_res
        else:
            ## 检查是否需要进行替换占位符的
            rlist_url = re.findall(r"##(.*?)##", api_url)
            for i in rlist_url:
                api_url = api_url.replace("##" + i + "##", str(eval(i)))

            rlist_header = re.findall(r"##(.*?)##", api_header)
            for i in rlist_header:
                api_header = api_header.replace("##" + i + "##", repr(str(eval(i))))

            if api_body_method == 'none':
                pass
            elif api_body_method == 'form-data' or api_body_method == 'x-www-form-urlencoded':

                rlist_body = re.findall(r"##(.*?)##", api_body)
                for i in rlist_body:
                    api_body = api_body.replace("##" + i + "##", str(eval(i)))
                print(api_body)
            elif api_body_method == 'Json':
                rlist_body = re.findall(r"##(.*?)##", api_body)
                for i in rlist_body:
                    api_body = api_body.replace("##" + i + "##", repr(eval(i)))
            else:
                rlist_body = re.findall(r"##(.*?)##", api_body)
                for i in rlist_body:
                    api_body = api_body.replace("##" + i + "##", str(eval(i)))

            if api_header == "":
                ts_header = '{}'
            ## 实际发送请求
            try:
                header = json.loads(api_header)  # 处理header
            except:
                header = eval(api_header)

            print(f"step.public_header ====>{step.public_header}")
            if step.public_header != "":
                ts_project_headers = step.public_header.split(',')  # 获取公共请求头
            # 遍历公共请求头，并把其加入到header字典中
                for i in ts_project_headers:
                    project_header = DB_project_header.objects.filter(id=i)[0]
                    header[project_header.key] = project_header.value



            ## 输出请求数据
            print('【host】：', api_host)
            print('【url】：', api_url)
            print('【header】：', header)
            print('【method】：', api_method)
            print('【body_method】：', api_body_method)
            print('【body】：', api_body)



            # 拼接完整url
            if api_host[-1] == '/' and api_url[0] == '/':  # 都有/
                url = api_host[:-1] + api_url
            elif api_host[-1] != '/' and api_url[0] != '/':  # 都没有/
                url = api_host + '/' + api_url
            else:  # 肯定有一个有/
                url = api_host + api_url

            # 登陆态
            api_login = step.api_login  # 获取登陆开关
            if api_login == 'yes':  # 需要判断
                try:
                    eval("login_res")
                    print('已调用过')
                except:
                    print('未调用过')
                    from api_test.views import project_login_send_for_other
                    project_id = DB_cases.objects.filter(id=DB_step.objects.filter(id=step.id)[0].Case_id)[0].project_id
                    global login_res
                    login_res = project_login_send_for_other(project_id)
                print(login_res)

                # 开始插入代码url/header/body

                ## url插入  过滤cookie持久化 对象a
                if '?' not in url:
                    url += '?'
                    if type(login_res) == dict:
                        for i in login_res.keys():
                            url += i + '=' + login_res[i] + '&'
                else:  # 证明已经有参数了
                    if type(login_res) == dict:
                        for i in login_res.keys():
                            url += '&' + i + '=' + login_res[i]
                ## header插入 过滤cookie持久化 对象a
                if type(login_res) == dict:
                    header.update(login_res)

            else:
                login_res = {}




            if api_body_method == 'none' or api_body_method == 'null':
                if type(login_res) == dict:
                    response = requests.request(api_method.upper(), url, headers=header, data={})
                else:
                    response = login_res.request(api_method.upper(), url, headers=header, data={})


            elif api_body_method == 'form-data':
                files = []
                payload = {}
                for i in eval(api_body):
                    payload[i[0]] = i[1]

                if type(login_res) == dict:
                    for i in login_res.keys():
                        payload[i] = login_res[i]
                    response = requests.request(api_method.upper(), url, headers=header, data=payload, files=files)
                else:
                    response = login_res.request(api_method.upper(), url, headers=header, data=payload, files=files)

            elif api_body_method == 'x-www-form-urlencoded':
                header['Content-Type'] = 'application/x-www-form-urlencoded'
                payload = {}
                for i in eval(api_body):
                    payload[i[0]] = i[1]
                for i in login_res.keys():
                    payload[i] = login_res[i]
                if type(login_res) == dict:
                    response = requests.request(api_method.upper(), url, headers=header, data=payload)
                else:
                    response = login_res.request(api_method.upper(), url, headers=header, data=payload)

            else:  # 这时肯定是raw的五个子选项：
                if api_body_method == 'Text':
                    header['Content-Type'] = 'text/plain'

                if api_body_method == 'JavaScript':
                    header['Content-Type'] = 'text/plain'

                if api_body_method == 'Json':
                    header['Content-Type'] = 'text/plain'
                    api_body = json.loads(api_body)
                    for i in login_res.keys():
                        api_body[i] = login_res[i]
                    api_body = json.dumps(api_body)

                if api_body_method == 'Html':
                    header['Content-Type'] = 'text/plain'

                if api_body_method == 'Xml':
                    header['Content-Type'] = 'text/plain'

                if type(login_res) == dict:
                    response = requests.request(api_method.upper(), url, headers=header, data=api_body.encode('utf-8'))
                else:
                    response = login_res.request(api_method.upper(), url, headers=header, data=api_body.encode('utf-8'))
            response.encoding = "utf-8"
            res = response.text

        DB_host.objects.update_or_create(host=api_host)

        print(f"【返回体】：{res}")

        # 对返回值res进行提取：

        # # 路径法提取：
        if get_path != '':  # 说明有设置
            for i in get_path.split('\n'):
                key = i.split('=')[0].rstrip()
                path = i.split('=')[1].lstrip()

                py_path = ""
                for j in path.split('/'):
                    if j != '':
                        if j[0] != '[':
                            py_path += '["%s"]' % j
                        else:
                            py_path += j
                value = eval("%s%s" % (json.loads(res), py_path))
                exec('global %s\n%s = value ' % (key, key))
        # # 正则法提取：
        if get_zz != '':  # 说明又设置
            for i in get_zz.split('\n'):
                key = i.split('=')[0].rstrip()
                zz = i.split('=')[1].lstrip()
                value = re.findall(zz, res)[0]
                exec('global %s\n%s = "%s" ' % (key, key, value))

        # 路径断言法
        if assert_path != '':
            for i in assert_path.split("\n"):
                path = i.split("=")[0].rstrip()
                expect = eval(i.split("=")[1].lstrip())
                py_path = ""
                for j in path.split('/'):
                    if j != '':
                        py_path += '["%s"]' % j
                    else:
                        py_path += j
                value = eval("%s%s" % (json.loads(res), py_path))
                self.assertEqual(expect, value, '不相等')

        # 正则断言法
        if assert_zz != '':
            for i in assert_zz.split("\n"):
                zz = i.split("=")[0].rstrip()
                expect = i.split("=")[1].lstrip()
                value = re.findall(zz,res)[0]
                self.assertEqual(expect,value,'不相等')

        # 全文检索
        if assert_qz != '':
            for i in assert_qz.split("\n"):
                if i not in res:
                    raise AssertionError("字符串不存在：%s" %i)






# 复制demo的结构给生成的测试用例
def make_defself(step):
    def tool(self):
        Test.demo(self, step)

    setattr(tool, "__doc__", u"%s" % step.name)
    return tool


# 动态生成测试用例
def make_def(steps):
    for i in range(len(steps)):
        setattr(Test, 'test_' + str(steps[i].index).zfill(3), make_defself(steps[i]))


def run(Case_id, Case_name, steps):
    make_def(steps)
    print('=' * 10)
    print(steps)
    suite = unittest.makeSuite(Test)
    filename = 'api_test/templates/Reports/%s.html' % Case_id
    r = bf(suite)
    r.report(description='用例描述%s' % Case_name, filename=filename)

# run()
